import { EventEmitter } from '../utils/EventEmitter';
import {
    InputEventType,
    InputEventData,
    InputEventHandler,
    InputManagerOptions,
    KeyState,
    MouseButton,
    MouseState,
    TouchPoint,
    TouchState
} from './types';

export class InputManager extends EventEmitter {
    private canvas: HTMLCanvasElement;
    private options: Required<InputManagerOptions>;
    
    // 键盘状态
    private keys: Map<string, KeyState>;
    
    // 鼠标状态
    private mouse: MouseState;
    
    // 触摸状态
    private touch: TouchState;
    
    // 事件处理器映射
    private eventHandlers: Map<InputEventType, Set<InputEventHandler>>;
    
    // 事件处理函数
    private handleKeyEvent: (event: KeyboardEvent) => void;
    private handleMouseEvent: (event: MouseEvent) => void;
    private handleTouchEvent: (event: TouchEvent) => void;
    
    constructor(canvas: HTMLCanvasElement, options: InputManagerOptions = {}) {
        super();
        
        this.canvas = canvas;
        this.options = {
            enableKeyboard: true,
            enableMouse: true,
            enableTouch: true,
            preventDefaultTouch: true,
            preventDefaultKeyboard: false,
            preventDefaultMouse: false,
            ...options
        };
        
        // 初始化状态
        this.keys = new Map();
        this.mouse = {
            x: 0,
            y: 0,
            buttons: new Map(),
            wheelDelta: 0,
            isInCanvas: false
        };
        this.touch = {
            points: new Map(),
            changedPoints: []
        };
        
        // 初始化事件处理器
        this.eventHandlers = new Map();
        Object.values(InputEventType).forEach(type => {
            this.eventHandlers.set(type, new Set());
        });
        
        // 初始化事件处理函数
        this.handleKeyEvent = this.createKeyEventHandler();
        this.handleMouseEvent = this.createMouseEventHandler();
        this.handleTouchEvent = this.createTouchEventHandler();
        
        // 绑定事件处理器
        this.bindEvents();
    }
    
    /**
     * 创建键盘事件处理函数
     */
    private createKeyEventHandler(): (event: KeyboardEvent) => void {
        return (event: KeyboardEvent) => {
            if (this.options.preventDefaultKeyboard) {
                event.preventDefault();
            }
            
            const key = event.key.toLowerCase();
            const timestamp = Date.now();
            
            // 更新按键状态
            const state: KeyState = {
                isPressed: event.type === InputEventType.KEY_DOWN,
                isRepeated: event.repeat,
                timestamp
            };
            this.keys.set(key, state);
            
            // 创建事件数据
            const eventData: InputEventData = {
                type: event.type as InputEventType,
                target: event.target || window,
                timestamp,
                preventDefault: () => event.preventDefault(),
                stopPropagation: () => event.stopPropagation(),
                key: event.key,
                code: event.code,
                keyCode: event.keyCode,
                repeat: event.repeat
            };
            
            // 触发事件
            this.emit(event.type, eventData);
            this.triggerHandlers(event.type as InputEventType, eventData);
        };
    }
    
    /**
     * 创建鼠标事件处理函数
     */
    private createMouseEventHandler(): (event: MouseEvent) => void {
        return (event: MouseEvent) => {
            if (this.options.preventDefaultMouse) {
                event.preventDefault();
            }
            
            const timestamp = Date.now();
            const rect = this.canvas.getBoundingClientRect();
            
            // 更新鼠标位置（相对于画布）
            this.mouse.x = event.clientX - rect.left;
            this.mouse.y = event.clientY - rect.top;
            
            // 更新按钮状态
            if (event.type === InputEventType.MOUSE_DOWN || event.type === InputEventType.MOUSE_UP) {
                this.mouse.buttons.set(event.button as MouseButton, event.type === InputEventType.MOUSE_DOWN);
            }
            
            // 更新滚轮状态
            if (event.type === InputEventType.MOUSE_WHEEL) {
                this.mouse.wheelDelta = (event as WheelEvent).deltaY;
            }
            
            // 更新鼠标进入/离开状态
            if (event.type === InputEventType.MOUSE_ENTER) {
                this.mouse.isInCanvas = true;
            } else if (event.type === InputEventType.MOUSE_LEAVE) {
                this.mouse.isInCanvas = false;
            }
            
            // 创建事件数据
            const eventData: InputEventData = {
                type: event.type as InputEventType,
                target: event.target || this.canvas,
                timestamp,
                preventDefault: () => event.preventDefault(),
                stopPropagation: () => event.stopPropagation(),
                button: event.button as MouseButton,
                buttons: event.buttons,
                clientX: event.clientX,
                clientY: event.clientY,
                movementX: event.movementX,
                movementY: event.movementY,
                wheelDelta: (event as WheelEvent).deltaY
            };
            
            // 触发事件
            this.emit(event.type, eventData);
            this.triggerHandlers(event.type as InputEventType, eventData);
        };
    }
    
    /**
     * 创建触摸事件处理函数
     */
    private createTouchEventHandler(): (event: TouchEvent) => void {
        return (event: TouchEvent) => {
            if (this.options.preventDefaultTouch) {
                event.preventDefault();
            }
            
            const timestamp = Date.now();
            const rect = this.canvas.getBoundingClientRect();
            
            // 更新触摸点状态
            const touches: TouchPoint[] = [];
            const changedTouches: TouchPoint[] = [];
            
            // 处理所有触摸点
            Array.from(event.touches).forEach(touch => {
                const point: TouchPoint = {
                    id: touch.identifier,
                    x: touch.clientX - rect.left,
                    y: touch.clientY - rect.top,
                    force: touch.force,
                    timestamp
                };
                touches.push(point);
                this.touch.points.set(point.id, point);
            });
            
            // 处理变化的触摸点
            Array.from(event.changedTouches).forEach(touch => {
                const point: TouchPoint = {
                    id: touch.identifier,
                    x: touch.clientX - rect.left,
                    y: touch.clientY - rect.top,
                    force: touch.force,
                    timestamp
                };
                changedTouches.push(point);
                
                if (event.type === InputEventType.TOUCH_END || event.type === InputEventType.TOUCH_CANCEL) {
                    this.touch.points.delete(point.id);
                }
            });
            
            this.touch.changedPoints = changedTouches;
            
            // 创建事件数据
            const eventData: InputEventData = {
                type: event.type as InputEventType,
                target: event.target || this.canvas,
                timestamp,
                preventDefault: () => event.preventDefault(),
                stopPropagation: () => event.stopPropagation(),
                touches,
                changedTouches
            };
            
            // 触发事件
            this.emit(event.type, eventData);
            this.triggerHandlers(event.type as InputEventType, eventData);
        };
    }
    
    /**
     * 绑定所有输入事件
     */
    private bindEvents(): void {
        if (this.options.enableKeyboard) {
            this.bindKeyboardEvents();
        }
        
        if (this.options.enableMouse) {
            this.bindMouseEvents();
        }
        
        if (this.options.enableTouch) {
            this.bindTouchEvents();
        }
    }
    
    /**
     * 绑定键盘事件
     */
    private bindKeyboardEvents(): void {
        window.addEventListener(InputEventType.KEY_DOWN, this.handleKeyEvent);
        window.addEventListener(InputEventType.KEY_UP, this.handleKeyEvent);
        window.addEventListener(InputEventType.KEY_PRESS, this.handleKeyEvent);
    }
    
    /**
     * 绑定鼠标事件
     */
    private bindMouseEvents(): void {
        this.canvas.addEventListener(InputEventType.MOUSE_DOWN, this.handleMouseEvent);
        this.canvas.addEventListener(InputEventType.MOUSE_UP, this.handleMouseEvent);
        this.canvas.addEventListener(InputEventType.MOUSE_MOVE, this.handleMouseEvent);
        this.canvas.addEventListener(InputEventType.MOUSE_WHEEL, this.handleMouseEvent);
        this.canvas.addEventListener(InputEventType.MOUSE_ENTER, this.handleMouseEvent);
        this.canvas.addEventListener(InputEventType.MOUSE_LEAVE, this.handleMouseEvent);
    }
    
    /**
     * 绑定触摸事件
     */
    private bindTouchEvents(): void {
        this.canvas.addEventListener(InputEventType.TOUCH_START, this.handleTouchEvent);
        this.canvas.addEventListener(InputEventType.TOUCH_END, this.handleTouchEvent);
        this.canvas.addEventListener(InputEventType.TOUCH_MOVE, this.handleTouchEvent);
        this.canvas.addEventListener(InputEventType.TOUCH_CANCEL, this.handleTouchEvent);
    }
    
    /**
     * 触发指定类型的所有事件处理器
     */
    private triggerHandlers(type: InputEventType, event: InputEventData): void {
        const handlers = this.eventHandlers.get(type);
        if (handlers) {
            handlers.forEach(handler => handler(event));
        }
    }
    
    /**
     * 添加事件处理器
     */
    public addEventListener(type: InputEventType, handler: InputEventHandler): void {
        const handlers = this.eventHandlers.get(type);
        if (handlers) {
            handlers.add(handler);
        }
    }
    
    /**
     * 移除事件处理器
     */
    public removeEventListener(type: InputEventType, handler: InputEventHandler): void {
        const handlers = this.eventHandlers.get(type);
        if (handlers) {
            handlers.delete(handler);
        }
    }
    
    /**
     * 检查按键是否被按下
     */
    public isKeyPressed(key: string): boolean {
        const state = this.keys.get(key.toLowerCase());
        return state?.isPressed || false;
    }
    
    /**
     * 获取按键状态
     */
    public getKeyState(key: string): KeyState | undefined {
        return this.keys.get(key.toLowerCase());
    }
    
    /**
     * 获取鼠标状态
     */
    public getMouseState(): MouseState {
        return { ...this.mouse };
    }
    
    /**
     * 检查鼠标按钮是否被按下
     */
    public isMouseButtonPressed(button: MouseButton): boolean {
        return this.mouse.buttons.get(button) || false;
    }
    
    /**
     * 获取触摸状态
     */
    public getTouchState(): TouchState {
        return {
            points: new Map(this.touch.points),
            changedPoints: [...this.touch.changedPoints]
        };
    }
    
    /**
     * 获取所有活动的触摸点
     */
    public getActiveTouchPoints(): TouchPoint[] {
        return Array.from(this.touch.points.values());
    }
    
    /**
     * 获取最近变化的触摸点
     */
    public getChangedTouchPoints(): TouchPoint[] {
        return [...this.touch.changedPoints];
    }
    
    /**
     * 重置所有输入状态
     */
    public reset(): void {
        // 重置键盘状态
        this.keys.clear();
        
        // 重置鼠标状态
        this.mouse.buttons.clear();
        this.mouse.wheelDelta = 0;
        
        // 重置触摸状态
        this.touch.points.clear();
        this.touch.changedPoints = [];
    }
    
    /**
     * 销毁输入管理器
     */
    public destroy(): void {
        // 移除所有事件监听器
        if (this.options.enableKeyboard) {
            window.removeEventListener(InputEventType.KEY_DOWN, this.handleKeyEvent);
            window.removeEventListener(InputEventType.KEY_UP, this.handleKeyEvent);
            window.removeEventListener(InputEventType.KEY_PRESS, this.handleKeyEvent);
        }
        
        if (this.options.enableMouse) {
            this.canvas.removeEventListener(InputEventType.MOUSE_DOWN, this.handleMouseEvent);
            this.canvas.removeEventListener(InputEventType.MOUSE_UP, this.handleMouseEvent);
            this.canvas.removeEventListener(InputEventType.MOUSE_MOVE, this.handleMouseEvent);
            this.canvas.removeEventListener(InputEventType.MOUSE_WHEEL, this.handleMouseEvent);
            this.canvas.removeEventListener(InputEventType.MOUSE_ENTER, this.handleMouseEvent);
            this.canvas.removeEventListener(InputEventType.MOUSE_LEAVE, this.handleMouseEvent);
        }
        
        if (this.options.enableTouch) {
            this.canvas.removeEventListener(InputEventType.TOUCH_START, this.handleTouchEvent);
            this.canvas.removeEventListener(InputEventType.TOUCH_END, this.handleTouchEvent);
            this.canvas.removeEventListener(InputEventType.TOUCH_MOVE, this.handleTouchEvent);
            this.canvas.removeEventListener(InputEventType.TOUCH_CANCEL, this.handleTouchEvent);
        }
        
        // 清空状态
        this.reset();
        
        // 清空事件处理器
        this.eventHandlers.clear();
        
        // 移除所有事件监听器
        this.removeAllListeners();
    }
} 